﻿using System;
using System.Linq;
using System.Collections.Generic;
using RayDen.Library.Entity.Scene;
using RayDen.Library.Entity.Interface;

namespace RayDen.Library.Entity.SceneGraph
{

    public class SceneGraphInfo
    {
        public string ID;
        public SceneGraphElement RootNode;


        public string SceneName { get; set; }
        public IParameterBag Parameters { get; set; }

        public void Visit(INodeVisitor visitor)
        {
            //VisitNode(RootNode, visitor);
            NodeAction(RootNode, visitor.Visit);
        }

        public void Visit(Action<SceneGraphElement> visitor)
        {
            NodeAction(RootNode, visitor);
        }

        private void VisitNode(SceneGraphElement node, INodeVisitor visitor)
        {
            visitor.Visit(node);
            if (node.Children.Count <= 0)
                return;
            foreach (var sceneElement in node.Children)
            {
                this.VisitNode(sceneElement, visitor);
            }
        }


        private void NodeAction(SceneGraphElement node, Action<SceneGraphElement> action)
        {
            action(node);
            if (node.Children.Count <= 0)
                return;
            foreach (var sceneElement in node.Children)
            {
                NodeAction(sceneElement, action);
            }
        }

        public TChildrenNode GetById<TChildrenNode>(int id)
            where TChildrenNode : SceneGraphElement
        {
            TChildrenNode result = null;
            NodeAction(this.RootNode, element =>
                {
                    if (element.Id == id && element.GetType() == typeof(TChildrenNode))
                    {
                        result = (TChildrenNode)element;
                    }
                });
            return result;
        }

        public TChildrenNode ResolveDataNode<TChildrenNode>(ReferenceNode rc)
          where TChildrenNode : SceneGraphElement
        {
            var rn = rc.FindRoot ?? this.RootNode;
            TChildrenNode result = null;
            NodeAction(rn, element =>
            {
                if (element.Id == rc.DataNodeId && element.GetType() == typeof(TChildrenNode))
                {
                    result = (TChildrenNode)element;
                }
            });
            return result;
        }

        /*
        public IEnumerable<TChildrenNode> GetChildren<TChildrenNode>()
            where TChildrenNode : SceneGraphElement
        {
            return GetChildren<TChildrenNode>(this.RootNode);
        }

        private IEnumerable<TChildrenNode> GetChildren<TChildrenNode>(SceneGraphElement node)
            where TChildrenNode : SceneGraphElement
        {
            var result = new List<TChildrenNode>();
            if (node.Children != null)
            {
                result.AddRange(node.Children.SelectMany(GetChildren<TChildrenNode>));
            }

            if (node is TChildrenNode)
            {
                result.Add((TChildrenNode)node);
            }
            return result;
        }
        */
    }
}